#include "TexMgr_Ogre.h"
#include "OgreTexture.h"
#include "OgrePixelFormat.h"
#include "OgreHardwarePixelBuffer.h"
#include "OgreColourValue.h"
#include "OgreTextureManager.h"
#include "OgreResourceGroupManager.h"

using namespace Ogre;

#define TERRAIN_HEIGHT 255

const std::string TexMgr_Ogre::ResGrpName = "TerrainRes"; //which is my ResGrpName in my cfg. you could tune it as you like.

TexMgr_Ogre::TexMgr_Ogre( void ):m_pTileTexInfo(0)
{

}


TexMgr_Ogre::~TexMgr_Ogre( void )
{
	Clear();
}

bool TexMgr_Ogre::LoadImg( const char* fileName )
{
	Ogre::Image* img = new Ogre::Image();
	img->load(fileName, ResGrpName);
	m_VecImg.push_back(img);
	return true;
}

bool TexMgr_Ogre::SaveImg( const char* fileName )
{
	return false;
}

void TexMgr_Ogre::GetColorValueAt(int iX, int iZ, float fHeight, int texIdx, float& r, float& g, float& b, float& a)
{
	Ogre::ColourValue val = m_VecImg[texIdx]->getColourAt(iX, iZ, 0);
	if((texIdx == 0) && (fHeight < m_pTileTexInfo[texIdx].iLow))
	{
		r = val[0];
		g = val[1];
		b = val[2];
		a = 1;
		return;
	}
	else if((texIdx == (m_VecImg.size()-1)) && (fHeight > m_pTileTexInfo[texIdx].iHigh))
	{
		r = val[0];
		g = val[1];
		b = val[2];
		a = 1;
		return;
	}
	float p = 1.0f;
	if((fHeight < m_pTileTexInfo[texIdx].iLow) || (fHeight > m_pTileTexInfo[texIdx].iHigh))
		p = 0;
	else if(fHeight < m_pTileTexInfo[texIdx].iOpt)
		p = (fHeight - m_pTileTexInfo[texIdx].iLow)/(m_pTileTexInfo[texIdx].iOpt - m_pTileTexInfo[texIdx].iLow);
	else if(fHeight > m_pTileTexInfo[texIdx].iOpt)
		p = (m_pTileTexInfo[texIdx].iHigh - fHeight)/(m_pTileTexInfo[texIdx].iHigh - m_pTileTexInfo[texIdx].iOpt);
	else
		p = 1.0f;
	r = val[0]*p;
	g = val[1]*p;
	b = val[2]*p;
}

int TexMgr_Ogre::GetImgCnt()
{
	return m_VecImg.size();
}

void TexMgr_Ogre::Clear()
{
	for(int i = 0; i<m_VecImg.size(); ++i)
	{
		delete m_VecImg[i];
	}

	if(m_pTileTexInfo)
		delete m_pTileTexInfo;
}

void TexMgr_Ogre::CalcTileDat()
{
	int _size = m_VecImg.size();
	if(_size == 0) return;
	if(m_pTileTexInfo)
		delete m_pTileTexInfo;
	m_pTileTexInfo = new STileTex[_size];
	int iLastHeight = -1;
	for(int i = 0; i < _size; ++i)
	{
		m_pTileTexInfo[i].iLow = iLastHeight + 1;
		iLastHeight += TERRAIN_HEIGHT/_size;
		m_pTileTexInfo[i].iOpt = iLastHeight;
		m_pTileTexInfo[i].iHigh = iLastHeight - m_pTileTexInfo[i].iLow + iLastHeight;
	}
}

void* TexMgr_Ogre::GenerateTexture( int iResolution, ITerrain* parent )
{
	CalcTileDat();

	//create manual texture
	Ogre::TexturePtr texPtr = Ogre::TextureManager::getSingleton().createManual("texP",
		Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		TEX_TYPE_2D, iResolution, iResolution, 0, PF_R8G8B8, TU_DEFAULT);

	char* tmpBuf = new char[iResolution*iResolution*4];
	Ogre::PixelBox tmpBox(iResolution,
		iResolution,
		texPtr->getDepth(),
		texPtr->getFormat(),
		tmpBuf);
	Ogre::HardwarePixelBufferSharedPtr tmpTexBuf = texPtr->getBuffer();
	tmpTexBuf->blitToMemory(tmpBox);
	Ogre::Image* tex = new Ogre::Image();
	tex->loadDynamicImage((Ogre::uchar*)tmpBox.data, tmpBox.getWidth(), tmpBox.getHeight(), tmpBox.format);

	int tmpX, tmpZ;
	float tmpCol[4] = {0};
	for(int iz = 0; iz < iResolution - 1; ++iz)
	{
		for(int ix = 0; ix < iResolution - 1 ; ++ix)
		{
			float fR = 0;
			float fG = 0;
			float fB = 0;
			for(int i = 0; i < GetImgCnt(); ++i)
			{
				tmpX = ix; tmpZ = iz;
				GetTexCoord(tmpX, tmpZ, i);
				GetColorValueAt(tmpX, tmpZ, 
					parent->InterpolateHeight(ix, iz, parent->GetSize()/iResolution),
					i, tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);

				fR += tmpCol[0];
				fG += tmpCol[1];
				fB += tmpCol[2];
			}
			Ogre::ColourValue c(fR,fG,fB);
			tex->setColourAt(c, ix, iz, 0);
		}
	}
	tex->save("GeneratedTexture.bmp");
	
	tmpTexBuf->blitFromMemory(tex->getPixelBox());

	delete tmpBuf;
	delete tex;

	return (void*)0;
}

void TexMgr_Ogre::GetTexCoord( int& ix, int& iz, int TexId)
{
	int width = m_VecImg[TexId]->getWidth();
	int wrapX = 0;
	for(int i = 1;;)
	{
		if(ix >= i*width)
			++wrapX;
		else
			break;
	}
	ix = ix - ix*wrapX;
	int wrapZ = 0;
	for(int i = 1;;)
	{
		if(ix >= i*width)
			++wrapZ;
		else
			break;
	}
	iz = iz - iz*wrapZ;
}
